package com.huawei.zyb.taskManager.application.task;

import com.huawei.zyb.taskManager.application.task.dto.*;
import com.huawei.zyb.taskManager.domain.developer.entity.Developer;
import com.huawei.zyb.taskManager.domain.developer.valueobject.DeveloperId;
import com.huawei.zyb.taskManager.domain.developer.repository.DeveloperRepository;
import com.huawei.zyb.taskManager.domain.requirement.entity.Requirement;
import com.huawei.zyb.taskManager.domain.requirement.valueobject.RequirementId;
import com.huawei.zyb.taskManager.domain.requirement.repository.RequirementRepository;
import com.huawei.zyb.taskManager.domain.task.entity.Task;
import com.huawei.zyb.taskManager.domain.task.repository.TaskRepository;
import com.huawei.zyb.taskManager.domain.task.valueobject.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务应用服务
 */
@Service
@Transactional
public class TaskApplicationService {
    
    private final TaskRepository taskRepository;
    private final RequirementRepository requirementRepository;
    private final DeveloperRepository developerRepository;
    
    public TaskApplicationService(
            TaskRepository taskRepository,
            RequirementRepository requirementRepository,
            DeveloperRepository developerRepository) {
        this.taskRepository = taskRepository;
        this.requirementRepository = requirementRepository;
        this.developerRepository = developerRepository;
    }
    
    /**
     * 创建任务
     */
    public TaskDTO createTask(CreateTaskCommand command) {
        System.out.println("[DEBUG] 开始创建任务: " + command.getTitle());
        System.out.println("[DEBUG] 任务参数: " + command);
        
        // 验证需求是否存在
        RequirementId requirementId = RequirementId.of(command.getRequirementId());
        Requirement requirement = requirementRepository.findById(requirementId)
            .orElseThrow(() -> new IllegalArgumentException("需求不存在: " + command.getRequirementId()));
        
        System.out.println("[DEBUG] 需求验证通过: " + requirement.getTitle().getValue());
        
        // 对于新任务，不设置ID，让数据库自动生成
        TaskId taskId = null;
        System.out.println("[DEBUG] 新任务将由数据库自动生成ID");
        
        // 创建任务
        Task task;
        if (command.getParentTaskId() != null) {
            // 创建子任务
            System.out.println("[DEBUG] 创建子任务，父任务ID: " + command.getParentTaskId());
            TaskId parentTaskId = TaskId.of(command.getParentTaskId());
            task = Task.createSubTask(
                taskId,
                TaskTitle.of(command.getTitle()),
                TaskDescription.of(command.getDescription()),
                command.getStatus(),
                command.getPriority(),
                command.getRequirementId(),
                command.getAssigneeId(),
                parentTaskId,
                command.getLevel(),
                command.getEstimatedHours() != null ? EstimatedHours.of(command.getEstimatedHours()) : null,
                command.getProgress() != null ? TaskProgress.of(command.getProgress()) : null,
                command.getActualHours() != null ? ActualHours.of(command.getActualHours()) : null
            );
        } else {
            // 创建主任务
            System.out.println("[DEBUG] 创建主任务");
            task = Task.create(
                taskId,
                TaskTitle.of(command.getTitle()),
                TaskDescription.of(command.getDescription()),
                command.getStatus(),
                command.getPriority(),
                command.getRequirementId(),
                command.getAssigneeId(),
                command.getEstimatedHours() != null ? EstimatedHours.of(command.getEstimatedHours()) : null,
                command.getProgress() != null ? TaskProgress.of(command.getProgress()) : null,
                command.getActualHours() != null ? ActualHours.of(command.getActualHours()) : null
            );
        }
        
        System.out.println("[DEBUG] 任务对象创建完成，准备保存到数据库");
        
        // 保存任务
        Task savedTask = taskRepository.save(task);
        
        System.out.println("[DEBUG] 任务保存完成，任务ID: " + savedTask.getId().getValue());
        
        TaskDTO result = convertToDTO(savedTask);
        System.out.println("[DEBUG] 任务创建成功，返回DTO: " + result.getTitle());
        
        return result;
    }
    
    /**
     * 分配任务
     */
    public void assignTask(Long taskId, String assigneeId) {
        Task task = findTaskByIdOrThrow(taskId);
        
        // 验证开发者是否存在且可分配任务
        DeveloperId developerId = DeveloperId.of(assigneeId);
        Developer developer = developerRepository.findById(developerId)
            .orElseThrow(() -> new IllegalArgumentException("开发者不存在: " + assigneeId));
        
        if (!developer.canBeAssignedTasks()) {
            throw new IllegalStateException("开发者当前状态不允许分配任务: " + assigneeId);
        }
        
        task.assignTo(assigneeId);
        taskRepository.save(task);
    }
    
    /**
     * 开始任务
     */
    public void startTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.IN_PROGRESS);
        taskRepository.save(task);
    }
    
    /**
     * 暂停任务并返回DTO
     */
    public TaskDTO pauseTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.PAUSED);
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 恢复任务并返回DTO
     */
    public TaskDTO resumeTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.IN_PROGRESS);
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 完成任务并返回DTO
     */
    public TaskDTO completeTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.COMPLETED);
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 取消任务并返回DTO
     */
    public TaskDTO cancelTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.CANCELLED);
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 更新任务进度并返回DTO
     */
    public TaskDTO updateTaskProgress(Long taskId, Integer progress) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateProgress(TaskProgress.of(progress.doubleValue()));
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 记录实际工时
     */
    public void recordActualHours(Long taskId, Double actualHours) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateActualHours(ActualHours.of(actualHours));
        taskRepository.save(task);
    }
    
    /**
     * 更新任务信息
     */
    public void updateTask(Long taskId, UpdateTaskCommand command) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateInfo(
            TaskTitle.of(command.getTitle()),
            TaskDescription.of(command.getDescription()),
            command.getPriority()
        );
        
        // 更新任务状态（只有当状态发生变化时才更新）
        if (command.getStatus() != null && !command.getStatus().equals(task.getStatus())) {
            task.updateStatus(command.getStatus());
        }
        
        // 更新预估工时
        if (command.getEstimatedHours() != null) {
            task.updateEstimatedHours(EstimatedHours.of(command.getEstimatedHours()));
        }
        
        // 更新实际工时
        if (command.getActualHours() != null) {
            task.updateActualHours(ActualHours.of(command.getActualHours()));
        }
        
        // 更新任务进度
        if (command.getProgress() != null) {
            task.updateProgress(TaskProgress.of(command.getProgress()));
        }
        
        taskRepository.save(task);
    }
    
    /**
     * 删除任务
     */
    public void deleteTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        
        // 检查是否有未完成的子任务
        if (taskRepository.hasIncompleteSubTasks(task.getId())) {
            throw new IllegalStateException("存在未完成的子任务，无法删除父任务: " + taskId);
        }
        
        taskRepository.deleteById(task.getId());
    }
    
    /**
     * 根据ID查找任务
     */
    @Transactional(readOnly = true)
    public TaskDTO findTaskById(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        return convertToDTO(task);
    }
    
    /**
     * 根据需求ID查找任务列表
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByRequirementId(Long requirementId) {
        List<Task> tasks = taskRepository.findByRequirementId(requirementId);
        return convertToDTOWithBatchRequirements(tasks);
    }
    
    /**
     * 根据指派人ID查找任务列表
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByAssigneeId(String assigneeId) {
        List<Task> tasks = taskRepository.findByAssigneeId(assigneeId);
        return convertToDTOWithBatchRequirements(tasks);
    }
    
    /**
     * 根据父任务ID查找子任务列表
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByParentTaskId(Long parentTaskId) {
        TaskId parentId = TaskId.of(parentTaskId);
        List<Task> tasks = taskRepository.findByParentTaskId(parentId);
        return tasks.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }
    
    /**
     * 根据状态查找任务列表
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByStatus(TaskStatus status) {
        List<Task> tasks = taskRepository.findByStatus(status);
        return tasks.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }
    
    /**
     * 根据层级查找任务列表
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByLevel(TaskLevel level) {
        List<Task> tasks = taskRepository.findByLevel(level);
        return tasks.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }
    
    /**
     * 查找所有任务
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findAllTasks() {
        List<Task> tasks = taskRepository.findAll();
        return convertToDTOWithBatchRequirements(tasks);
    }
    
    /**
     * 递归查找所有子任务
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findAllSubTasks(Long parentTaskId) {
        TaskId parentId = TaskId.of(parentTaskId);
        List<Task> tasks = taskRepository.findByParentTaskId(parentId);
        return tasks.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }
    
    /**
     * 更新任务状态
     */
    public void updateTaskStatus(Long taskId, TaskStatus status) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(status);
        taskRepository.save(task);
    }
    
    /**
     * 批量更新任务
     */
    public void batchUpdateTasks(BatchUpdateTaskCommand command) {
        switch (command.getOperationType()) {
            case UPDATE_STATUS:
                batchUpdateTaskStatus(command.getTaskIds(), command.getStatus());
                break;
            case UPDATE_ASSIGNEE:
                batchAssignTasks(command.getTaskIds(), command.getAssigneeId());
                break;
            case UPDATE_PRIORITY:
                batchUpdatePriority(command.getTaskIds(), command.getPriority());
                break;
            case DELETE:
                batchDeleteTasks(command.getTaskIds());
                break;
            default:
                throw new IllegalArgumentException("不支持的批量操作类型: " + command.getOperationType());
        }
    }
    
    private void batchUpdateTaskStatus(List<Long> taskIds, TaskStatus status) {
        for (Long taskId : taskIds) {
            Task task = findTaskByIdOrThrow(taskId);
            task.updateStatus(status);
            taskRepository.save(task);
        }
    }
    
    private void batchAssignTasks(List<Long> taskIds, String assigneeId) {
        for (Long taskId : taskIds) {
            assignTask(taskId, assigneeId);
        }
    }
    
    private void batchUpdatePriority(List<Long> taskIds, TaskPriority priority) {
        for (Long taskId : taskIds) {
            Task task = findTaskByIdOrThrow(taskId);
            task.updateInfo(task.getTitle(), task.getDescription(), priority);
            taskRepository.save(task);
        }
    }
    
    private void batchDeleteTasks(List<Long> taskIds) {
        for (Long taskId : taskIds) {
            deleteTask(taskId);
        }
    }

    /**
     * 根据需求ID和状态查找任务
     */
    @Transactional(readOnly = true)
    public List<TaskDTO> findTasksByRequirementIdAndStatus(Long requirementId, TaskStatus status) {
        return taskRepository.findByRequirementId(requirementId).stream()
            .filter(task -> task.getStatus() == status)
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }
    
    /**
     * 统计任务数量
     */
    @Transactional(readOnly = true)
    public long countTasks() {
        return taskRepository.findAll().size();
    }
    
    /**
     * 统计指派人的任务数量
     */
    @Transactional(readOnly = true)
    public long countTasksByAssigneeId(String assigneeId) {
        return taskRepository.findByAssigneeId(assigneeId).size();
    }
    
    /**
     * 获取任务统计信息
     */
    @Transactional(readOnly = true)
    public TaskStatisticsDTO getTaskStatistics() {
        // 使用Repository层的聚合查询，避免加载所有数据到内存
        long totalTasks = taskRepository.count();
        
        // 按状态统计
        Map<String, Long> statusCount = new HashMap<>();
        for (TaskStatus status : TaskStatus.values()) {
            long count = taskRepository.countByStatus(status);
            statusCount.put(status.name(), count);
        }
        
        // 按优先级统计
        Map<String, Long> priorityCount = new HashMap<>();
        for (TaskPriority priority : TaskPriority.values()) {
            long count = taskRepository.countByPriority(priority);
            priorityCount.put(priority.name(), count);
        }
        
        // 完成率
        long completedTasks = taskRepository.countByStatus(TaskStatus.COMPLETED);
        double completionRate = totalTasks == 0 ? 0.0 : (double) completedTasks / totalTasks * 100;
        
        return new TaskStatisticsDTO(
            totalTasks,
            statusCount,
            priorityCount,
            Math.round(completionRate * 100.0) / 100.0
        );
    }
    
    /**
     * 重新打开任务
     */
    public TaskDTO reopenTask(Long taskId) {
        Task task = findTaskByIdOrThrow(taskId);
        task.updateStatus(TaskStatus.TODO);
        taskRepository.save(task);
        return convertToDTO(task);
    }
    
    /**
     * 分页查询任务（带筛选条件）
     */
    @Transactional(readOnly = true)
    public Page<TaskDTO> findTasksWithFilters(Pageable pageable, Map<String, Object> filters) {
        // 这里简化实现，实际应该在Repository层实现复杂查询
        List<Task> allTasks = taskRepository.findAll();
        
        // 应用筛选条件
        List<Task> filteredTasks = allTasks.stream()
            .filter(task -> applyFilters(task, filters))
            .collect(Collectors.toList());
        
        // 转换为DTO
        List<TaskDTO> taskDTOs = filteredTasks.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
        
        // 应用排序（按需求排序）
        if (pageable.getSort().isSorted()) {
            taskDTOs = applySorting(taskDTOs, pageable);
        }
        
        // 简化的分页实现
        int start = (int) pageable.getOffset();
        int end = Math.min(start + pageable.getPageSize(), taskDTOs.size());
        List<TaskDTO> pageContent = start < taskDTOs.size() ? taskDTOs.subList(start, end) : new ArrayList<>();
        
        return new PageImpl<>(pageContent, pageable, taskDTOs.size());
    }
    
    private List<TaskDTO> applySorting(List<TaskDTO> taskDTOs, Pageable pageable) {
        return taskDTOs.stream()
            .sorted((task1, task2) -> {
                for (org.springframework.data.domain.Sort.Order order : pageable.getSort()) {
                    String property = order.getProperty();
                    boolean isAsc = order.isAscending();
                    
                    int comparison = 0;
                    switch (property) {
                        case "requirement":
                            String req1 = task1.getRequirementTitle() != null ? task1.getRequirementTitle() : "";
                            String req2 = task2.getRequirementTitle() != null ? task2.getRequirementTitle() : "";
                            comparison = req1.compareTo(req2);
                            break;
                        case "id":
                            comparison = task1.getId().compareTo(task2.getId());
                            break;
                        case "title":
                            comparison = task1.getTitle().compareTo(task2.getTitle());
                            break;
                        case "status":
                            comparison = task1.getStatus().compareTo(task2.getStatus());
                            break;
                        case "priority":
                            comparison = task1.getPriority().compareTo(task2.getPriority());
                            break;
                        case "createdAt":
                            comparison = task1.getCreatedAt().compareTo(task2.getCreatedAt());
                            break;
                        default:
                            comparison = 0;
                    }
                    
                    if (comparison != 0) {
                        return isAsc ? comparison : -comparison;
                    }
                }
                return 0;
            })
            .collect(Collectors.toList());
    }
    
    private boolean applyFilters(Task task, Map<String, Object> filters) {
        if (filters.containsKey("status") && !task.getStatus().equals(filters.get("status"))) {
            return false;
        }
        if (filters.containsKey("priority") && !task.getPriority().equals(filters.get("priority"))) {
            return false;
        }
        if (filters.containsKey("assignee") && (task.getAssigneeId() == null || !task.getAssigneeId().contains((String) filters.get("assignee")))) {
            return false;
        }
        if (filters.containsKey("requirement") && (task.getRequirementId() == null || !task.getRequirementId().toString().contains((String) filters.get("requirement")))) {
            return false;
        }
        if (filters.containsKey("title") && (task.getTitle() == null || !task.getTitle().getValue().toLowerCase().contains(((String) filters.get("title")).toLowerCase()))) {
            return false;
        }
        return true;
    }
    
    private Task findTaskByIdOrThrow(Long taskId) {
        TaskId id = TaskId.of(taskId);
        return taskRepository.findById(id)
            .orElseThrow(() -> new IllegalArgumentException("任务不存在: " + taskId));
    }
    
    private TaskDTO convertToDTO(Task task) {
        TaskDTO dto = new TaskDTO();
        dto.setId(task.getId().getValue());
        dto.setTitle(task.getTitle().getValue());
        dto.setDescription(task.getDescription() != null ? task.getDescription().getValue() : null);
        dto.setStatus(task.getStatus());
        dto.setPriority(task.getPriority());
        dto.setLevel(task.getLevel());
        dto.setProgress(task.getProgress().getValue().intValue());
        dto.setEstimatedHours(task.getEstimatedHours() != null ? task.getEstimatedHours().getValue().doubleValue() : null);
        dto.setActualHours(task.getActualHours() != null ? task.getActualHours().getValue().doubleValue() : null);
        dto.setRequirementId(task.getRequirementId());
        
        // 查询需求标题
        String requirementTitle = null;
        if (task.getRequirementId() != null) {
            requirementTitle = requirementRepository.findById(RequirementId.of(task.getRequirementId()))
                    .map(requirement -> requirement.getTitle().getValue())
                    .orElse(null);
        }
        dto.setRequirementTitle(requirementTitle);
        
        dto.setAssigneeId(task.getAssigneeId());
        dto.setParentTaskId(task.getParentTaskId() != null ? task.getParentTaskId().getValue() : null);
        dto.setCreatedAt(task.getCreatedAt());
        dto.setUpdatedAt(task.getUpdatedAt());
        return dto;
    }
    
    /**
     * 批量转换任务为DTO，优化需求查询性能
     */
    private List<TaskDTO> convertToDTOWithBatchRequirements(List<Task> tasks) {
        if (tasks.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 收集所有需求ID
        Set<Long> requirementIds = tasks.stream()
                .map(Task::getRequirementId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        
        // 批量查询需求信息
        Map<Long, String> requirementTitleMap = new HashMap<>();
        if (!requirementIds.isEmpty()) {
            Set<RequirementId> reqIds = requirementIds.stream()
                    .map(RequirementId::of)
                    .collect(Collectors.toSet());
            
            requirementRepository.findAll()
                    .stream().filter(requirement -> reqIds.contains(requirement.getId()))
                    .forEach(requirement -> 
                            requirementTitleMap.put(
                                    requirement.getId().getValue(),
                                    requirement.getTitle().getValue()
                            )
                    );
        }
        
        // 转换为DTO
        return tasks.stream()
                .map(task -> convertToDTOWithRequirementMap(task, requirementTitleMap))
                .collect(Collectors.toList());
    }
    
    /**
     * 使用需求标题映射转换任务为DTO
     */
    private TaskDTO convertToDTOWithRequirementMap(Task task, Map<Long, String> requirementTitleMap) {
        TaskDTO dto = new TaskDTO();
        dto.setId(task.getId().getValue());
        dto.setTitle(task.getTitle().getValue());
        dto.setDescription(task.getDescription() != null ? task.getDescription().getValue() : null);
        dto.setStatus(task.getStatus());
        dto.setPriority(task.getPriority());
        dto.setLevel(task.getLevel());
        dto.setProgress(task.getProgress().getValue().intValue());
        dto.setEstimatedHours(task.getEstimatedHours() != null ? task.getEstimatedHours().getValue().doubleValue() : null);
        dto.setActualHours(task.getActualHours() != null ? task.getActualHours().getValue().doubleValue() : null);
        dto.setRequirementId(task.getRequirementId());
        
        // 从映射中获取需求标题
        String requirementTitle = null;
        if (task.getRequirementId() != null) {
            requirementTitle = requirementTitleMap.get(task.getRequirementId());
        }
        dto.setRequirementTitle(requirementTitle);
        
        dto.setAssigneeId(task.getAssigneeId());
        dto.setParentTaskId(task.getParentTaskId() != null ? task.getParentTaskId().getValue() : null);
        dto.setCreatedAt(task.getCreatedAt());
        dto.setUpdatedAt(task.getUpdatedAt());
        return dto;
    }
}